﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Moonwish.Silverlight.OsAvatar.Windows
{
    /// <summary>
    /// 系统窗口，普通程序将以创建此窗口的方式展现。
    /// write by zhlin 2012-02-23
    /// </summary>
    public class AvatarWindow : ContentControl
    {
        private Border _border;
        private CaptionBar _captionBar;
        private Image _captionIcon;
        private TextBlock _captionText;
        private ContentPresenter _contentpresenter;
        private static int _currentZIndex = 1;
        private bool _draggingEnabled;
        
        private const int HotSpotWidth = 3;
        private Point _initialDragPoint;
        private Point _initialResizePoint;
        private Point _initialWindowLocation;
        private Size _initialWindowSize;
        private double _innerContentPresenterOffset;
        private bool _isDragging;
        private bool _isMaximized;
        private bool _isResizing;
        

        private const int MinWindowWidth = 100;

        private ResizeAnchor _resizeAnchor;
        private bool _resizeEnabled;
        private ScrollViewer _scrollcontent;

        private bool _showMaxButton;
        private bool _showMinButton;
        
        private Grid _window;

        public event EventHandler Closed;
        public event EventHandler Dragged;
        public event EventHandler Maximized;
        public event EventHandler Minimized;
        public event EventHandler Normalized;
        public EventHandler SetZIndex;

        public AvatarWindow()
        {
            _innerContentPresenterOffset = -1.0;
            _showMinButton = true;
            _showMaxButton = true;
            _draggingEnabled = true;
            _resizeEnabled = true;
            DefaultStyleKey = typeof(AvatarWindow);
            LayoutUpdated += WindowLayoutUpdated;
        }

        public AvatarWindow(bool isMinButton, bool isMaxButton)
        {
            _innerContentPresenterOffset = -1.0;
            _showMinButton = true;
            _showMaxButton = true;
            _draggingEnabled = true;
            _resizeEnabled = true;
            _showMinButton = isMinButton;
            _showMaxButton = isMaxButton;
            DefaultStyleKey = typeof(AvatarWindow);
            LayoutUpdated += WindowLayoutUpdated;
        }

        public void ApplyTheme()
        {
            if (_captionBar != null)
            {
                //captionBar.Background = ((App)Application.Current).CurrentTheme.WindowsCaptionBrush;
            }
            if (_border != null)
            {
                //border.BorderBrush = ((App)Application.Current).CurrentTheme.WindowsOuterBorderBrush;
                //border.Background = ((App)Application.Current).CurrentTheme.WindowsInnerBorderBrush;
            }
        }

        private void CaptionBarMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (DraggingEnabled)
            {
                Canvas.SetZIndex(this, _currentZIndex++);
                if (SetZIndex != null)
                {
                    SetZIndex(this, EventArgs.Empty);
                }
                ((FrameworkElement)sender).CaptureMouse();
                _initialDragPoint = e.GetPosition(Parent as UIElement);
                _initialWindowLocation.X = Canvas.GetLeft(this);
                _initialWindowLocation.Y = Canvas.GetTop(this);
                _isDragging = true;
            }
        }

        private void CaptionBarMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (DraggingEnabled)
            {
                ((FrameworkElement)sender).ReleaseMouseCapture();
                _isDragging = false;
            }
        }

        private void CaptionBarMouseMove(object sender, MouseEventArgs e)
        {
            if (_isDragging)
            {
                var position = e.GetPosition(Parent as UIElement);
                var parent = (Canvas)Parent;
                double length = (_initialWindowLocation.X + position.X) - _initialDragPoint.X;
                if ((length >= 0.0) && ((length + _captionBar.ActualWidth) <= parent.ActualWidth))
                {
                    Canvas.SetLeft(this, length);
                }
                double num2 = (_initialWindowLocation.Y + position.Y) - _initialDragPoint.Y;
                if ((num2 >= 0.0) && ((num2 + _captionBar.ActualHeight) <= parent.ActualHeight))
                {
                    Canvas.SetTop(this, num2);
                }
                if (Dragged != null)
                {
                    Dragged(this, EventArgs.Empty);
                }
            }
        }

        public void Close()
        {
            Visibility = Visibility.Collapsed;
            if (Closed != null)
            {
                Closed(this, EventArgs.Empty);
            }
        }

        private void CloseButtonClick(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void DefineDragEvents()
        {
            if (_captionBar != null)
            {
                _captionBar.MouseLeftButtonDown += CaptionBarMouseLeftButtonDown;
                _captionBar.MouseMove += CaptionBarMouseMove;
                _captionBar.MouseLeftButtonUp += CaptionBarMouseLeftButtonUp;
            }
        }

        private void DefineResizeEvents()
        {
            if (_window != null)
            {
                _window.MouseLeftButtonDown += WindowMouseLeftButtonDown;
                _window.MouseMove += WindowMouseMove;
                _window.MouseLeftButtonUp += WindowMouseLeftButtonUp;
            }
        }

        private void MaxButtonClick(object sender, RoutedEventArgs e)
        {
            Maximize();
        }

        public void Maximize()
        {
            if (!_isMaximized)
            {
                _initialWindowSize.Width = !double.IsNaN(Width) ? Width : ActualWidth;
                _initialWindowSize.Height = !double.IsNaN(Height) ? Height : ActualHeight;
                _initialWindowLocation.X = Canvas.GetLeft(this);
                _initialWindowLocation.Y = Canvas.GetTop(this);
                var parent = (FrameworkElement)Parent;
                Canvas.SetLeft(this, 0);
                Canvas.SetTop(this, 0);
                Width = parent.RenderSize.Width;
                Height = parent.RenderSize.Height;
                if (Maximized != null)
                {
                    Maximized(this, EventArgs.Empty);
                }
                _isDragging = false;
                _isResizing = false;
            }
            else
            {
                Canvas.SetLeft(this, _initialWindowLocation.X);
                Canvas.SetTop(this, _initialWindowLocation.Y);
                Width = _initialWindowSize.Width;
                Height = _initialWindowSize.Height;
                if (Normalized != null)
                {
                    Normalized(this, EventArgs.Empty);
                }
            }
            _isMaximized = !_isMaximized;
            _draggingEnabled = !_isMaximized;
            _resizeEnabled = !_isMaximized;
            SetContentPresenterWidth();
        }

        private void MinButtonClick(object sender, RoutedEventArgs e)
        {
            Visibility = Visibility.Collapsed;
            if (Minimized != null)
            {
                Minimized(this, EventArgs.Empty);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _window = (Grid)GetTemplateChild("PART_Window");
            _scrollcontent = (ScrollViewer)GetTemplateChild("PART_ScrollContent");
            _scrollcontent.HorizontalScrollBarVisibility = HorizontalScrollBarVisibility;
            _scrollcontent.VerticalScrollBarVisibility = VerticalScrollBarVisibility;
            _contentpresenter = (ContentPresenter)GetTemplateChild("PART_ContentPresenter");
            _border = (Border)GetTemplateChild("PART_Border");
            _captionBar = (CaptionBar)GetTemplateChild("PART_CaptionBar");
            var templateChild = (Button)GetTemplateChild("PART_MinButton");
            if (templateChild != null)
            {
                templateChild.Click += MinButtonClick;
                if (!_showMinButton)
                {
                    templateChild.Visibility = Visibility.Collapsed;
                }
            }
            var button2 = (Button)GetTemplateChild("PART_MaxButton");
            if (button2 != null)
            {
                button2.Click += MaxButtonClick;
                if (!_showMaxButton)
                {
                    button2.Visibility = Visibility.Collapsed;
                }
            }
            var button3 = (Button)GetTemplateChild("PART_CloseButton");
            if (button3 != null)
            {
                button3.Click += CloseButtonClick;
            }
            DefineDragEvents();
            DefineResizeEvents();
            Canvas.SetZIndex(this, _currentZIndex);
            if (SetZIndex != null)
            {
                SetZIndex(this, EventArgs.Empty);
            }
            _captionBar.DoubleClick += CaptionBarDoubleClick;
        }

        /// <summary>
        /// 标题栏双击事件。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void CaptionBarDoubleClick(object sender, EventArgs e)
        {
            if (_showMaxButton)
            {
                Maximize();
            }
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            Canvas.SetZIndex(this, _currentZIndex++);
            if (SetZIndex != null)
            {
                SetZIndex(this, EventArgs.Empty);
            }
        }

        private static void OnHorizontalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = d as AvatarWindow;
            if ((window != null) && (window._scrollcontent != null))
            {
                window._scrollcontent.HorizontalScrollBarVisibility = (ScrollBarVisibility)e.NewValue;
            }
        }

        private static void OnVerticalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = d as AvatarWindow;
            if ((window != null) && (window._scrollcontent != null))
            {
                window._scrollcontent.VerticalScrollBarVisibility = (ScrollBarVisibility)e.NewValue;
            }
        }

        private void ResizeBottom(double deltaY)
        {
            Height = Math.Max(_initialWindowSize.Height + deltaY, _captionBar.ActualHeight);
        }

        private void ResizeLeft(double deltaX)
        {
            double num = (_initialWindowLocation.X + _initialWindowSize.Width) - 60.0;
            Canvas.SetLeft(this, Math.Min(_initialResizePoint.X + deltaX, num));
            Width = Math.Max(_initialWindowSize.Width - deltaX, 60.0);
        }

        private void ResizeRight(double deltaX)
        {
            Width = Math.Max(_initialWindowSize.Width + deltaX, 60.0);
        }

        private void ResizeTop(double deltaY)
        {
            double num = (_initialWindowLocation.Y + _initialWindowSize.Height) - _captionBar.ActualHeight;
            Canvas.SetTop(this, Math.Min(_initialResizePoint.Y + deltaY, num));
            Height = Math.Max(_initialWindowSize.Height - deltaY, _captionBar.ActualHeight);
        }

        private void SetContentPresenterSizeAndMinSize()
        {
            if (_contentpresenter.Content == null)
            {
                return;
            }
            _contentpresenter.Width = ActualWidth - _innerContentPresenterOffset;
            if (HorizontalScrollBarVisibility != ScrollBarVisibility.Hidden)
            {
                _contentpresenter.MinWidth = ((FrameworkElement)_contentpresenter.Content).MinWidth;
            }
            if (VerticalScrollBarVisibility != ScrollBarVisibility.Hidden)
            {
                _contentpresenter.MinHeight = ((FrameworkElement)_contentpresenter.Content).MinHeight;
            }
        }

        private void SetContentPresenterWidth()
        {
            double num = Width - _innerContentPresenterOffset;
            double num2 = (Height - 30.0) - _innerContentPresenterOffset;
            _contentpresenter.Width = (num > 0.0) ? num : 0.0;
            _contentpresenter.Height = (num2 > 0.0) ? num2 : 0.0;
        }

        private void WindowLayoutUpdated(object sender, EventArgs e)
        {
            if ((Math.Abs(_innerContentPresenterOffset + 1.0) <= 0) && (_scrollcontent != null))
            {
                _innerContentPresenterOffset = ActualWidth - ((((((_scrollcontent.ActualWidth - _scrollcontent.Margin.Left) - _scrollcontent.Margin.Right) - _scrollcontent.Padding.Left) - _scrollcontent.Padding.Right) - _scrollcontent.BorderThickness.Left) - _scrollcontent.BorderThickness.Right);
                _innerContentPresenterOffset = Math.Max(_innerContentPresenterOffset, 0.0);
                SetContentPresenterSizeAndMinSize();
            }
        }

        private void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (CanResize)
            {
                ((FrameworkElement)sender).CaptureMouse();
                _initialResizePoint = e.GetPosition(Parent as UIElement);
                _initialWindowSize.Width = !double.IsNaN(Width) ? Width : ActualWidth;
                _initialWindowSize.Height = !double.IsNaN(Height) ? Height : ActualHeight;
                _initialWindowLocation.X = Canvas.GetLeft(this);
                _initialWindowLocation.Y = Canvas.GetTop(this);
                _isResizing = true;
            }
        }

        private void WindowMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (ResizeEnabled && _isResizing)
            {
                ((FrameworkElement)sender).ReleaseMouseCapture();
                _isResizing = false;
            }
        }

        private void WindowMouseMove(object sender, MouseEventArgs e)
        {
            if (ResizeEnabled)
            {
                if (!_isResizing)
                {
                    Point position = e.GetPosition(_window);
                    if ((position.Y <= 3.0) && (position.X <= 3.0))
                    {
                        _window.Cursor = Cursors.Hand;
                        _resizeAnchor = ResizeAnchor.TopLeft;
                    }
                    else if ((position.Y <= 3.0) && (position.X >= (_window.ActualWidth - 3.0)))
                    {
                        _window.Cursor = Cursors.Hand;
                        _resizeAnchor = ResizeAnchor.TopRight;
                    }
                    else if (position.Y <= 3.0)
                    {
                        _window.Cursor = Cursors.SizeNS;
                        _resizeAnchor = ResizeAnchor.Top;
                    }
                    else if ((position.Y >= (_window.ActualHeight - 3.0)) && (position.X <= 3.0))
                    {
                        _window.Cursor = Cursors.Hand;
                        _resizeAnchor = ResizeAnchor.BottomLeft;
                    }
                    else if ((position.Y >= (_window.ActualHeight - 3.0)) && (position.X >= (_window.ActualWidth - 3.0)))
                    {
                        _window.Cursor = Cursors.Hand;
                        _resizeAnchor = ResizeAnchor.BottomRight;
                    }
                    else if (position.Y >= (_window.ActualHeight - 3.0))
                    {
                        _window.Cursor = Cursors.SizeNS;
                        _resizeAnchor = ResizeAnchor.Bottom;
                    }
                    else if (position.X <= 3.0)
                    {
                        _window.Cursor = Cursors.SizeWE;
                        _resizeAnchor = ResizeAnchor.Left;
                    }
                    else if (position.X >= (_window.ActualWidth - 3.0))
                    {
                        _window.Cursor = Cursors.SizeWE;
                        _resizeAnchor = ResizeAnchor.Right;
                    }
                    else
                    {
                        _window.Cursor = null;
                        _resizeAnchor = ResizeAnchor.None;
                    }
                }
                else
                {
                    var point2 = e.GetPosition(Parent as UIElement);
                    double deltaX = point2.X - _initialResizePoint.X;
                    double deltaY = point2.Y - _initialResizePoint.Y;
                    switch (_resizeAnchor)
                    {
                        case ResizeAnchor.Left:
                            ResizeLeft(deltaX);
                            break;

                        case ResizeAnchor.TopLeft:
                            ResizeLeft(deltaX);
                            ResizeTop(deltaY);
                            break;

                        case ResizeAnchor.Top:
                            ResizeTop(deltaY);
                            break;

                        case ResizeAnchor.TopRight:
                            ResizeRight(deltaX);
                            ResizeTop(deltaY);
                            break;

                        case ResizeAnchor.Right:
                            ResizeRight(deltaX);
                            break;

                        case ResizeAnchor.BottomRight:
                            ResizeRight(deltaX);
                            ResizeBottom(deltaY);
                            break;

                        case ResizeAnchor.Bottom:
                            ResizeBottom(deltaY);
                            break;

                        case ResizeAnchor.BottomLeft:
                            ResizeLeft(deltaX);
                            ResizeBottom(deltaY);
                            break;
                    }
                    SetContentPresenterWidth();
                }
            }
        }

        // Properties
        private bool CanResize
        {
            get
            {
                return (ResizeEnabled && (_resizeAnchor != ResizeAnchor.None));
            }
        }

        /// <summary>
        /// 标题
        /// </summary>
        public string Caption
        {
            get { return (string)GetValue(CaptionProperty); }
            set { SetValue(CaptionProperty, value); }
        }
        /// <summary>
        /// 标题
        /// </summary>
        public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption",
                                                                                                typeof(string),
                                                                                                typeof(AvatarWindow),
                                                                                                new PropertyMetadata(
                                                                                                    string.Empty));

        public bool DraggingEnabled
        {
            get
            {
                return _draggingEnabled;
            }
            set
            {
                _draggingEnabled = value;
            }
        }

        public ScrollBarVisibility HorizontalScrollBarVisibility
        {
            get
            {
                return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty);
            }
            set
            {
                SetValue(HorizontalScrollBarVisibilityProperty, value);
            }
        }
        public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(AvatarWindow), new PropertyMetadata(OnHorizontalScrollBarVisibilityPropertyChanged));

        /// <summary>
        /// 图标
        /// </summary>
        public ImageSource Favicon
        {
            get { return (ImageSource)GetValue(FaviconProperty); }
            set { SetValue(FaviconProperty, value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty FaviconProperty = DependencyProperty.Register("Favicon",
                                                                                                typeof(ImageSource),
                                                                                                typeof(CaptionBar),
                                                                                                new PropertyMetadata(
                                                                                                    new BitmapImage(new Uri("/Moonwish.Silverlight.OsAvatar;component/Icons/app64.png", UriKind.Relative))));

        public ImageSource MaxImageSource
        {
            get
            {
                return (BitmapImage)GetValue(MaxImageSourceProperty);
            }
            set
            {
                SetValue(MaxImageSourceProperty, value);
            }
        }
        public static readonly DependencyProperty MaxImageSourceProperty = DependencyProperty.Register("MaxImageSource", typeof(ImageSource), typeof(AvatarWindow), null);

        public bool ResizeEnabled
        {
            get
            {
                return _resizeEnabled;
            }
            set
            {
                _resizeEnabled = value;
            }
        }

        public ScrollBarVisibility VerticalScrollBarVisibility
        {
            get
            {
                return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty);
            }
            set
            {
                SetValue(VerticalScrollBarVisibilityProperty, value);
            }
        }
        public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(AvatarWindow), new PropertyMetadata(OnVerticalScrollBarVisibilityPropertyChanged));

        private enum ResizeAnchor
        {
            None,
            Left,
            TopLeft,
            Top,
            TopRight,
            Right,
            BottomRight,
            Bottom,
            BottomLeft
        }
    }
}
